package repository

import (
	"context"
	"encoding/json"
	"github.com/ecodeclub/ekit/slice"
	"jk-time/webook/feed/dao"
	"jk-time/webook/feed/domain"
	"time"
)

type FeedRepository interface {
	CreatePushEvents(ctx context.Context, fp []domain.FeedEvent) error
	CreatePullEvents(ctx context.Context, fp domain.FeedEvent) error
	FindPullEventList(ctx context.Context, uid []int64, timestamp, limit int64) ([]domain.FeedEvent, error)
	FindPullEventListWithTyp(ctx context.Context, typ string, uids []int64, timestamp,
		limit int64) ([]domain.FeedEvent, error)
	FindPushEventList(ctx context.Context, uid int64, timestamp, limit int64) ([]domain.FeedEvent, error)
	FindPushEventListWithTyp(ctx context.Context, typ string, uids int64, timestamp,
		limit int64) ([]domain.FeedEvent, error)
}
type feedRepository struct {
	pullDao dao.FeedPullEventDAO
	pushDao dao.FeedPushEventDAO
}

func NewFeedRepository(pullDao dao.FeedPullEventDAO, pushDao dao.FeedPushEventDAO) FeedRepository {
	return &feedRepository{pullDao: pullDao, pushDao: pushDao}
}

func (f feedRepository) FindPullEventList(ctx context.Context, uid []int64, timestamp, limit int64) ([]domain.FeedEvent, error) {
	events, err := f.pullDao.FindPullEventList(ctx, uid, timestamp, limit)
	if err != nil {
		return nil, err
	}
	ans := make([]domain.FeedEvent, 0, len(events))
	for _, e := range events {
		ans = append(ans, f.pullToDomain(e))
	}
	return ans, nil
}

func (f feedRepository) FindPullEventListWithTyp(ctx context.Context, typ string, uids []int64, timestamp, limit int64) ([]domain.FeedEvent, error) {
	events, err := f.pullDao.FindPullEventListWithTyp(ctx, typ, uids, timestamp, limit)
	if err != nil {
		return nil, err
	}
	ans := make([]domain.FeedEvent, 0, len(events))
	for _, e := range events {
		ans = append(ans, f.pullToDomain(e))
	}
	return ans, nil
}

func (f feedRepository) FindPushEventList(ctx context.Context, uid int64, timestamp, limit int64) ([]domain.FeedEvent, error) {
	events, err := f.pushDao.FindPushEventList(ctx, uid, timestamp, limit)
	if err != nil {
		return nil, err
	}
	ans := make([]domain.FeedEvent, 0, len(events))
	for _, e := range events {
		ans = append(ans, f.pushToDomain(e))
	}
	return ans, nil
}

func (f feedRepository) FindPushEventListWithTyp(ctx context.Context, typ string, uids int64, timestamp, limit int64) ([]domain.FeedEvent, error) {
	events, err := f.pushDao.FindPushEventListWithTyp(ctx, typ, uids, timestamp, limit)
	if err != nil {
		return nil, err
	}
	ans := make([]domain.FeedEvent, 0, len(events))
	for _, e := range events {
		ans = append(ans, f.pushToDomain(e))
	}
	return ans, nil
}

func (f feedRepository) CreatePullEvents(ctx context.Context, fp domain.FeedEvent) error {
	return f.pullDao.CreatePullEvents(ctx, f.toEntityPull(fp))
}

func (f feedRepository) CreatePushEvents(ctx context.Context, fp []domain.FeedEvent) error {
	fpe := slice.Map(fp, func(idx int, src domain.FeedEvent) dao.FeedPushEvent {
		return f.toEntityPush(src)
	})
	return f.pushDao.CreatePushEvents(ctx, fpe)
}
func (f feedRepository) toEntityPush(fe domain.FeedEvent) dao.FeedPushEvent {
	val, _ := json.Marshal(fe.Ext)
	return dao.FeedPushEvent{
		Id:      fe.ID,
		Uid:     fe.Uid,
		Type:    fe.Type,
		Content: string(val),
		Ctime:   fe.Ctime.UnixMilli(),
	}
}
func (f feedRepository) toEntityPull(fe domain.FeedEvent) dao.FeedPullEvent {
	val, _ := json.Marshal(fe.Ext)
	return dao.FeedPullEvent{
		Id:      fe.ID,
		Uid:     fe.Uid,
		Type:    fe.Type,
		Content: string(val),
		Ctime:   fe.Ctime.UnixMilli(),
	}
}
func (f feedRepository) pullToDomain(p dao.FeedPullEvent) domain.FeedEvent {
	var ext map[string]string
	_ = json.Unmarshal([]byte(p.Content), &ext)
	return domain.FeedEvent{
		ID:    p.Id,
		Uid:   p.Uid,
		Type:  p.Type,
		Ctime: time.Unix(p.Ctime, 0),
		Ext:   ext,
	}
}
func (f feedRepository) pushToDomain(p dao.FeedPushEvent) domain.FeedEvent {
	var ext map[string]string
	_ = json.Unmarshal([]byte(p.Content), &ext)
	return domain.FeedEvent{
		ID:    p.Id,
		Uid:   p.Uid,
		Type:  p.Type,
		Ctime: time.Unix(p.Ctime, 0),
		Ext:   ext,
	}
}
